library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
--use ieee.std_logic_arith.all;


entity complete_testbench is
end complete_testbench;


architecture Behavioral of complete_testbench is

  -- file
  type     bit_vector_file is file of bit_vector;
  file read_file       : bit_vector_file open read_mode is "output.hex";
  signal read_byte : std_logic_vector(7 downto 0);


	-- debug
	signal usb_write : std_logic := '0';
	
	signal timeout_debug : std_logic;
	
	signal valid_usb_data : unsigned(7 downto 0);
	signal valid_usb_data_en : std_logic;
	
	-- clocks
	signal clk_150 : std_logic := '1';
	
	-- wires
	signal usb_rec_valid : std_logic := '0';
	signal usb_rec_value: unsigned(7 downto 0) := (others => '0');
	
	signal usb_fifo_words : std_logic_vector(8 downto 0) := (others => '0');
	
	signal module_data_valid : std_logic;
	signal module_data : unsigned(7 downto 0);
	signal to_module : unsigned(7 downto 0);
	
	signal usb_out_valid : std_logic;
	signal usb_out : unsigned(7 downto 0); 
	signal usb_out_empty : std_logic;
	
	
	CONSTANT      num_requester_read      : natural := 3;
	constant      num_requester_write     : natural := 2;
	constant      num_frame_sender		  : natural := 1;
	
	
	signal request_write      : unsigned (num_requester_write-1 DOWNTO 0);
	signal request_read       : unsigned (num_requester_read-1 DOWNTO 0);
	signal in_sram_wr_addr    : std_logic_vector((18*num_requester_write)-1 DOWNTO 0);
	signal in_sram_wr_data    : std_logic_vector((16*num_requester_write)-1 DOWNTO 0);
	signal in_sram_rq_addr    : std_logic_vector((18*num_requester_read)-1 DOWNTO 0); 
	signal sram_scheduling_done_write : std_logic;
	signal sram_scheduling_nr_write : std_logic_vector (num_requester_write-1 DOWNTO 0);
	signal sram_scheduling_done_read : std_logic;
	signal sram_scheduling_nr_read : std_logic_vector (num_requester_read-1 DOWNTO 0);
	signal out_sram_read_addr     : std_logic_vector(17 DOWNTO 0);
	signal out_sram_read_data     : std_logic_vector(15 DOWNTO 0);
	signal out_sram_read_valid    : std_logic;
	
	signal sram_addr     : std_logic_vector(17 DOWNTO 0);
  signal sram_data     : std_logic_vector(15 DOWNTO 0);
  signal sram_wren     : std_logic; 

	
	signal request_frame            :  unsigned (num_frame_sender-1 DOWNTO 0);
    signal in_to_send_frame         :   std_logic_vector((8*num_frame_sender)-1 DOWNTO 0);
    signal fifo_halffull_frame      :   std_logic := '0';
    signal write_enable_frame       :    std_logic_vector(num_frame_sender-1 DOWNTO 0);
    signal schedule_nr_out_frame    :  std_logic_vector (num_frame_sender-1 DOWNTO 0);
    signal scheduling_done_out_frame :  std_logic;
    signal read_enable_frame        :   std_logic;
    signal out_to_send_frame        :   std_logic_vector(7 DOWNTO 0);
    signal data_to_fifo_we_frame    :   std_logic;

  
  signal ledr : std_logic_vector(9 downto 0);
  
  signal clock_counter : unsigned(31 downto 0) := (others => '0');
  
  
  ------
  type t_send_activate is array(1 to 6) of unsigned(7 downto 0);
  signal to_send_activate : t_send_activate := (
  "11111110" , "00000000", "00000100", "00000001", "00111100", -- header
   "00000001"); -- activate core 1
  
  type t_send_1_byte is array(1 to 5) of unsigned(7 downto 0);
  signal to_send_1_byte : t_send_1_byte := (
  "11111110" , "00000000", "00000001", "00000101", "00111100"); -- header for 1 word write
  
  type t_send_get_1byte is array(1 to 8) of unsigned(7 downto 0);
  signal to_send_get_1byte : t_send_get_1byte := (
  "11111110" , "00000000", "00000010", "00000011", "00111100",
  "00001000" , "00000000", "01111111"); -- header for 1 word write
  ------
	
	
	component framedecoder is Port 
	( 	clk : in  STD_LOGIC;
		usb_data_valid : in std_logic;
		usb_data : in unsigned(7 downto 0);
		module_data_valid : out std_logic;
		module_data : out unsigned(7 downto 0);
		to_module : out unsigned(7 downto 0)
	);		 
	end component;
	
	
	component sram_access IS
    GENERIC(
       num_requester_read      : natural := 4;
       num_requester_write      : natural := 4
    );
    PORT( 
       clk                : IN   std_logic;
       request_write      : IN   unsigned (num_requester_write-1 DOWNTO 0);
       request_read       : IN   unsigned (num_requester_read-1 DOWNTO 0);
       in_sram_wr_addr    : in std_logic_vector((18*num_requester_write)-1 DOWNTO 0);
       in_sram_wr_data    : in std_logic_vector((16*num_requester_write)-1 DOWNTO 0);
       in_sram_rq_addr    : in std_logic_vector((18*num_requester_read)-1 DOWNTO 0); 
       sram_scheduling_done_write : out std_logic;
       sram_scheduling_nr_write : out std_logic_vector (num_requester_write-1 DOWNTO 0);
       sram_scheduling_done_read : out std_logic;
       sram_scheduling_nr_read : out std_logic_vector (num_requester_read-1 DOWNTO 0);
       out_sram_read_addr     : out   std_logic_vector(17 DOWNTO 0);
       out_sram_read_data     : out   std_logic_vector(15 DOWNTO 0);
       out_sram_read_valid    : out   std_logic;
       sram_addr     : out   std_logic_vector(17 DOWNTO 0);
       sram_data     : inout std_logic_vector(15 DOWNTO 0);
       sram_wren          : out   std_logic 
    );
    end component;


	component led_updater IS
    GENERIC(
       mem_addr      : std_logic_vector(17 downto 0) := "000000000001111111";
       slowness      : natural := 20
    );
    PORT( 
       clk                : IN std_logic;  
       grant              : IN std_logic;  
       grant_valid        : IN std_logic;
       sram_read_addr     : in std_logic_vector(17 DOWNTO 0);
       sram_read_data     : in std_logic_vector(15 DOWNTO 0);
       sram_read_valid    : IN std_logic;
       request_out      : out std_logic;
       request_addr     : out std_logic_vector(17 DOWNTO 0);
       led_value        : out std_logic_vector(9 downto 0)  
    );
    end component;
  
  
    component extern_sram_writer IS
    PORT( 
       clk                : IN std_logic;  
       datain             : IN unsigned(7 downto 0);  
       datain_valid       : IN std_logic;  
       module_enable	  : IN std_logic;
       grant              : IN std_logic;  
       grant_valid        : IN std_logic;
       request_out      : out std_logic;
       request_data     : out std_logic_vector(15 DOWNTO 0);
       request_addr     : out std_logic_vector(17 DOWNTO 0)
    );
    end component;
    
    
    component framesend_unit IS
    GENERIC(
       num_requester      : natural := 4
    );
    PORT( 
       clk                : IN   std_logic;
       request            : IN   unsigned (num_requester-1 DOWNTO 0);
       in_to_send         : in   std_logic_vector((8*num_requester)-1 DOWNTO 0);
       fifo_halffull      : in   std_logic;
       write_enable       : in    std_logic_vector(num_requester-1 DOWNTO 0);
       schedule_nr_out    : out std_logic_vector (num_requester-1 DOWNTO 0);
       scheduling_done_out : out std_logic;
       read_enable        : out   std_logic;
       out_to_send        : out   std_logic_vector(7 DOWNTO 0);
       data_to_fifo_we    : out   std_logic
    );
    end component;
  
    
    component sram_streamer IS
    PORT( 
       clk                : IN std_logic;  
       datain             : IN unsigned(7 downto 0);  
       datain_valid       : IN std_logic; 
       module_enable	     : IN std_logic;
       grant              : IN std_logic;  
       grant_valid        : IN std_logic;
       sram_read_addr     : in std_logic_vector(17 DOWNTO 0);
       sram_read_data     : in std_logic_vector(15 DOWNTO 0);
       sram_read_valid    : IN std_logic;
       request_sram      : out std_logic;
       request_addr      : out std_logic_vector(17 DOWNTO 0);  
       frame_rden        : in std_logic;
       grant_frame       : in std_logic;
       grant_frame_valid : in std_logic;
       request_frame     : out std_logic;
       data_to_frame     : out std_logic_vector(7 DOWNTO 0);
       frame_wren        : out std_logic      
    );
    end component;

	 component sram_emu IS
    PORT( 
       sram_addr          : in   std_logic_vector(17 DOWNTO 0);
       sram_data          : inout std_logic_vector(15 DOWNTO 0);
       sram_wren          : in   std_logic 
    );
   end component; 
   
   
   component cores_enviroment IS
   GENERIC (
            cores      : natural := 1
        );
   Port(
        clk		             : IN STD_LOGIC;
        
        datain            : IN unsigned(7 downto 0);  
        datain_valid      : IN std_logic;
        module_enable	    : IN std_logic;          
        --sram read interface
        sram_read_addr    : in std_logic_vector(17 DOWNTO 0);
        sram_read_data    : in std_logic_vector(15 DOWNTO 0);
        sram_read_valid   : IN std_logic;
        grant_read        : IN std_logic;  
        grant_valid_read  : IN std_logic;
        request_out_read  : out std_logic;
        request_addr_read : out std_logic_vector(17 DOWNTO 0); 
        --sram write interface
        grant_write            : IN std_logic;  
        grant_valid_write      : IN std_logic;
        request_out_write      : out std_logic;
        request_data_write     : out std_logic_vector(15 DOWNTO 0);
        request_addr_write     : out std_logic_vector(17 DOWNTO 0) 
    );
    END component;
   
   
	
	
--############################################################################	
begin
--############################################################################

	
	framedecoder1 : framedecoder Port map 
	( 	clk => clk_150,
		usb_data_valid => usb_rec_valid,
		usb_data => usb_rec_value,
		module_data_valid => module_data_valid,
		module_data => module_data,
		to_module => to_module
	);	
	
	
	
	sram_access1 : sram_access
	GENERIC map(
       num_requester_read     => num_requester_read,
       num_requester_write    => num_requester_write
    )
    PORT map( 
       clk               => clk_150,
       request_write     => request_write,
       request_read       => request_read,
       in_sram_wr_addr    => in_sram_wr_addr,
       in_sram_wr_data    => in_sram_wr_data,
       in_sram_rq_addr   => in_sram_rq_addr,
       sram_scheduling_done_write => sram_scheduling_done_write,
       sram_scheduling_nr_write => sram_scheduling_nr_write,
       sram_scheduling_done_read => sram_scheduling_done_read,
       sram_scheduling_nr_read => sram_scheduling_nr_read,
       out_sram_read_addr  => out_sram_read_addr,
       out_sram_read_data  => out_sram_read_data,
       out_sram_read_valid => out_sram_read_valid,
       sram_addr  => sram_addr,
       sram_data => sram_data,
       sram_wren   => sram_wren
    );
    
    
    extern_sram_writer1 : extern_sram_writer
    PORT map( 
       clk                => clk_150,  
       datain             => module_data, 
       datain_valid       => module_data_valid,
       module_enable 	  => to_module(0),  
       grant              => sram_scheduling_nr_write(0), 
       grant_valid        => sram_scheduling_done_write,
       request_out      => request_write(0),
       request_data     => in_sram_wr_data(15 downto 0),
       request_addr     => in_sram_wr_addr(17 downto 0)
    );


	led_updater1 : led_updater
    GENERIC map(
       mem_addr      =>  "000000000001111111",
       slowness      => 8
    )
    PORT map( 
       clk            => clk_150, 
       grant          => sram_scheduling_nr_read(0),  
       grant_valid       => sram_scheduling_done_read,
       sram_read_addr     => out_sram_read_addr,
       sram_read_data     => out_sram_read_data,
       sram_read_valid    => out_sram_read_valid,
       request_out      => request_read(0),
       request_addr     => in_sram_rq_addr(17 downto 0),
       led_value        => ledr  
    );


	framesend_unit1 : framesend_unit
    GENERIC map(
       num_requester      => num_frame_sender
    )
    PORT map( 
       clk                => clk_150,
       request            => request_frame,
       in_to_send         => in_to_send_frame,
       fifo_halffull      => usb_fifo_words(8),
       write_enable       => write_enable_frame,
       schedule_nr_out    => schedule_nr_out_frame,
       scheduling_done_out => scheduling_done_out_frame,
       read_enable        => read_enable_frame,
       out_to_send        => out_to_send_frame,
       data_to_fifo_we    => data_to_fifo_we_frame
    );
        
        
    sram_streamer1 : sram_streamer 
    PORT map( 
       clk                => clk_150,  
       datain             => module_data,
       datain_valid       => module_data_valid,
       module_enable 	  => to_module(1),  
       grant              => sram_scheduling_nr_read(1),
       grant_valid        => sram_scheduling_done_read,
       sram_read_addr     => out_sram_read_addr,
       sram_read_data     => out_sram_read_data,
       sram_read_valid    => out_sram_read_valid,
       request_sram      => request_read(1),
       request_addr      => in_sram_rq_addr(35 downto 18),
       frame_rden        => read_enable_frame,
       grant_frame       => schedule_nr_out_frame(0),
       grant_frame_valid => scheduling_done_out_frame,
       request_frame     => request_frame(0),
       data_to_frame     => in_to_send_frame,
       frame_wren        => write_enable_frame(0)    
    );
    
    sram_emu1 : sram_emu
    PORT map( 
       sram_addr          => sram_addr,
       sram_data          => sram_data,
       sram_wren          => sram_wren
    );
    
    cores_enviroment1 : cores_enviroment
    GENERIC map(
            cores      => 1
        )
    Port map(
        clk		             => clk_150,
        
        datain            => module_data, 
        datain_valid      => module_data_valid,
        module_enable	     => to_module(2),  
                   
        sram_read_addr     => out_sram_read_addr,
        sram_read_data     => out_sram_read_data,
        sram_read_valid    => out_sram_read_valid,
        grant_read              => sram_scheduling_nr_read(2),
        grant_valid_read        => sram_scheduling_done_read,
        request_out_read        => request_read(2),
        request_addr_read       => in_sram_rq_addr(53 downto 36),
      
        grant_write            => sram_scheduling_nr_write(1),
        grant_valid_write      => sram_scheduling_done_write,
        request_out_write      => request_write(1),
        request_data_write     => in_sram_wr_data(31 downto 16),
        request_addr_write     => in_sram_wr_addr(35 downto 18)
    );
		
	
	 clk_150 <= not clk_150 after 5 ns;
	 
	 clock_counter <= clock_counter + 1 after 10 ns;
	 
	 process begin
	   wait for 50 ns;
	   --to_send_1_byte
	   --for i in 1 to 62 loop
	   --  usb_rec_valid<='1';
	   --  usb_rec_value<=to_send(i);
	   --  wait for 10 ns;
	   --  usb_rec_valid<='0';
	   --  wait for 100 ns;
	   --end loop;
	   wait;
	 end process;
	 
	 process 
    variable next_vector : bit_vector (0 downto 0);
    variable actual_len  : natural;
    variable addr        : unsigned(17 downto 0) := (others => '0');
    
    function CONV_STD_LOGIC_VECTOR(ARG: INTEGER; SIZE: INTEGER) return STD_LOGIC_VECTOR is
	variable result: STD_LOGIC_VECTOR (SIZE-1 downto 0);
	variable temp: integer;
	-- synopsys built_in SYN_INTEGER_TO_SIGNED
	-- synopsys subpgm_id 381
    begin
	-- synopsys synthesis_off
	temp := ARG;
	for i in 0 to SIZE-1 loop
	    if (temp mod 2) = 1 then
		result(i) := '1';
	    else 
		result(i) := '0';
	    end if;
	    if temp > 0 then
		temp := temp / 2;
	    elsif (temp > integer'low) then
		temp := (temp - 1) / 2; -- simulate ASR
	    else
		temp := temp / 2; -- simulate ASR
	    end if;
	end loop;
	return result;
	-- synopsys synthesis_on
    end;

    
    
   begin
  
    while not endfile(read_file) loop
      
      for i in 1 to 5 loop
	     usb_rec_valid<='1';
	     usb_rec_value<=to_send_1_byte(i);
	     wait for 10 ns;
	     usb_rec_valid<='0';
	     wait for 100 ns;
	    end loop;
      
      usb_rec_valid<='1';
	    usb_rec_value<="000010" & addr(17 downto 16);
	    wait for 10 ns;
	    usb_rec_valid<='0';
	    wait for 100 ns;
	    usb_rec_valid<='1';
	    usb_rec_value<=addr(15 downto 8);
	    wait for 10 ns;
	    usb_rec_valid<='0';
	    wait for 100 ns;
      usb_rec_valid<='1';
	    usb_rec_value<=addr(7 downto 0);
	    wait for 10 ns;
	    usb_rec_valid<='0';
	    wait for 100 ns;
      
      for i in 1 to 2 loop
        read(read_file, next_vector, actual_len);  
        read_byte <= CONV_STD_LOGIC_VECTOR(bit'pos(next_vector(0)), 8);
        wait for 10 ns;
        usb_rec_valid<='1';
	      usb_rec_value<=unsigned(read_byte);
	      wait for 10 ns;
	      usb_rec_valid<='0';
	      wait for 100 ns;
	    end loop;
      
      addr := addr +1;
      
    end loop;
    
    for i in 1 to 6 loop
	     usb_rec_valid<='1';
	     usb_rec_value<=to_send_activate(i);
	     wait for 10 ns;
	     usb_rec_valid<='0';
	     wait for 100 ns;
	  end loop;
	  
	  wait for 100 us;
	  
	  for i in 1 to 8 loop
	     usb_rec_valid<='1';
	     usb_rec_value<=to_send_get_1byte(i);
	     wait for 10 ns;
	     usb_rec_valid<='0';
	     wait for 100 ns;
	  end loop;  
    
    wait;
    
  end process;

	 

end Behavioral;









